﻿// RussianBlock.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <graphics.h> 
#include <time.h> 

void NexTipDis();
void ProdBlock();
void RefreInfo();
const char ROW = 20;
const char COL = 10;
const char StepSize = 30;
const char NexTipRow = 2;
const char NexTipCol = 11;
char AllBlock[20][10] = { 0 };
char Block[6][4] = {
{ 0, 1, 5, 6 },
{ 4, 5, 6, 7 },
{ 1, 4, 5, 6 },
{ 0, 4, 5, 6 },
{ 1, 2, 5, 6 },
{ 1, 2, 4, 5 }
};
unsigned char CurrBlo[4];
unsigned char Buff[4];
unsigned short Cleans = 0;
int Delay = 300;
char CurrSty = 0;
char NextSty = 0;
char DirX = 0;
bool RefreSign = false;
bool IsRun = true;
bool LongPresAble = false;
TCHAR GameInfo[15];
COORD RotaOrig = { 4, 1 };
IMAGE ImgBlo[6];
IMAGE ImgTem;
ExMessage msg;
//初始化 
void Init()
{
	srand((unsigned int)time(NULL));
	initgraph(500, 600);
	HWND hwnd = GetHWnd();
	SetWindowText(hwnd, _T("俄罗斯方块"));
	setbkcolor(WHITE);
	cleardevice();
	setlinecolor(BLACK);
	line(301, 0, 301, 600); loadimage(&ImgTem, _T("..\\Block.png"), 6 * StepSize, StepSize);
	SetWorkingImage(&ImgTem);
	for (int i = 0; i < 6; i++)
		getimage(&ImgBlo[i], StepSize * i, 0, StepSize, StepSize);

	SetWorkingImage();
	settextstyle(24, 0, _T("Consolas"));
	settextcolor(BLACK);
	outtextxy(3 * StepSize, 10 * StepSize, _T("SPACE"));
	outtextxy(11 * StepSize, 1 * StepSize, _T("Next:"));
	RefreInfo();
}
//消除行数显示 
void RefreInfo()
{
	_stprintf_s(GameInfo, _T("Cleans:%4d"), Cleans);
	outtextxy(11 * StepSize, 11 * StepSize, GameInfo);
}
//显示下一个方块样式 
void NexTipDis()
{
	do
	{
		NextSty = rand() % 6;
	} while (CurrSty == NextSty);
	clearrectangle(StepSize * 11, StepSize * 3, StepSize * (11 + 4), StepSize * (3 + 2));
	for (int i = 0; i < 4; i++) 	putimage(StepSize * (Block[NextSty][i] % 4 + 11), StepSize *
		(Block[NextSty][i] / 4 + 3), &ImgBlo[NextSty]);
	FlushBatchDraw();
}
//产生新的方块 
void ProdBlock()
{
	RotaOrig.X = 4;
	RotaOrig.Y = 1;
	CurrSty = NextSty;
	LongPresAble = false;
	Delay = 300;
	for (int i = 0; i < 4; i++)
		CurrBlo[i] = (Block[CurrSty][i] / 4) * 10 + (Block[CurrSty][i] % 4) + 3;
	NexTipDis();
}
void Drop()
{
	//旋转点Y坐标加一 
	RotaOrig.Y++;
	//下落之前备份 
	for (int i = 0; i < 4; i++)
		Buff[i] = CurrBlo[i];

	for (int j = 0; j < 4; j++)
	{
		CurrBlo[j] += 10;
		//失败 
		if (AllBlock[0][CurrBlo[j] % 10] != 0)
		{
			IsRun = false;
			return;
		}
		//非法 落地或重叠 
		if (CurrBlo[j] / 10 == 20 || AllBlock[CurrBlo[j] / 10][CurrBlo[j] % 10] !=
			0)
		{
			for (int i = 0; i < 4; i++)
				AllBlock[Buff[i] / 10][Buff[i] % 10] = CurrSty + 1;
			ProdBlock();
			break;
		}
	}
}
void MoveX()
{
	char BeforeRow = 0;
	RefreSign = true;
	//旋转点X坐标向左或右移动一个单位 
	RotaOrig.X += DirX;
	for (int i = 0; i < 4; i++)
		Buff[i] = CurrBlo[i];
	for (int j = 0; j < 4; j++)
	{
		BeforeRow = CurrBlo[j] / 10;
		CurrBlo[j] += DirX;
		//非法 
		if (AllBlock[CurrBlo[j] / 10][CurrBlo[j] % 10] != 0 || BeforeRow !=
			CurrBlo[j] / 10)
		{
			for (int i = 0; i < 4; i++)
				CurrBlo[i] = Buff[i];
			RotaOrig.X -= DirX;
			RefreSign = false;
			break;
		}
	}
	DirX = 0;
}
void CleanRow(char Row)
{

	RefreInfo();
	for (int i = 0; i < Row; i++)
	{
		for (int j = 0; j < 10; j++)
			AllBlock[Row - i][j] = AllBlock[Row - i - 1][j];
	}
}
void Refresh()
{
	char BlockCount = 0;
	RefreSign = false;
	clearrectangle(0, 0, StepSize * COL, StepSize * ROW);
	for (int i = 0; i < 4; i++)
	{
		putimage(StepSize * (CurrBlo[i] % 10), StepSize * (CurrBlo[i] / 10),
			&ImgBlo[CurrSty]);
	}
	for (int r = 0; r < ROW; r++)
	{
		for (int c = 0; c < COL; c++)
		{
			if (AllBlock[r][c])
			{
				putimage(StepSize * c, StepSize * r, &ImgBlo[AllBlock[r][c] -
					1]);
				if (COL == ++BlockCount)
				{
					Cleans++;
					CleanRow(r);
					BlockCount = 0;
				}
			}
		}
		BlockCount = 0;
	}
	FlushBatchDraw();
}
//方块 90°旋转处理 
void Rotate()
{
	char Col = 0;
	char Row = 0;
	if (CurrSty == 4) return;
	for (int i = 0; i < 4; i++)
	{
		Col = RotaOrig.X + ((CurrBlo[i] / 10) - RotaOrig.Y);
		Row = RotaOrig.Y + (RotaOrig.X - (CurrBlo[i] % 10));
		//非法 
		if (AllBlock[Row][Col] != 0 || Col < 0 || Col >= 10)  return;

		//合法 
		Buff[i] = Row * 10 + Col;
	}
	//合法 
	RefreSign = true;
	for (int j = 0; j < 4; j++)
		CurrBlo[j] = Buff[j];
}
//消息处理 
void MsgProce()
{
	if (peekmessage(&msg, EM_KEY))
	{
		if (msg.prevdown != 1)
		{
			switch (msg.vkcode)
			{
			case VK_LEFT: DirX = -1; break;
			case VK_RIGHT: DirX = 1; break;
			case VK_UP: Rotate(); break;
			case VK_DOWN: Delay = 70; break;
			}
			LongPresAble = true;
		}
		else if (msg.vkcode == VK_DOWN && LongPresAble == true) Delay = 70;
	}
}

int main(void)
{
	clock_t BegT;
	char Count = 0;
	Init();
	BeginBatchDraw();
	do
	{
		ProdBlock();
		//等待空格按下 空格按下开始游戏 
		do
		{
			getmessage(&msg, EM_KEY);
		} while (msg.vkcode != VK_SPACE);
		ProdBlock();
		RefreInfo();
		Refresh();
		BegT = clock();
		//游戏循环 
		while (IsRun)
		{
			MsgProce();

			if (clock() - BegT > Delay)
			{
				Drop();
				RefreSign = true;
				if (Delay == 70) Count++;
				if (Count >= 3)
				{
					Delay = 300;
					Count = 0;
				}
				BegT = clock();
			}
			if (DirX != 0)  MoveX();
			if (RefreSign)  Refresh();
			Sleep(5);
		}
		IsRun = true;
		Cleans = 0;
		clearrectangle(0, 0, StepSize * COL, StepSize * ROW);
		outtextxy(3 * StepSize, 9 * StepSize, _T("GAME OVER"));
		for (int i = 0; i < 20; i++)
			for (int j = 0; j < 10; j++)
				AllBlock[i][j] = 0;
	} while (true);
	EndBatchDraw();
	closegraph();
	return 0;
}


// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
